//============================================================================
// Copyright (C) 2003-2013 Brett R. Jones 
//
// Issued to public domain 2013
//
// brettjones1900@gmail.com
// http://www.p2panarchy.com
//============================================================================
#include "VxResolveHost.h"
#include <VxUtilLib/VxParse.h>
#include <VxUtilLib/VxSktUtil.h>
#include <VxUtilLib/VxGlobals.h>
#include <VxUtilLib/vx_debug.h>
#include <stdio.h>
#include <memory.h>

#ifdef WIN_PLATFORM
#include "Winsock2.h"
#include <Ws2tcpip.h>  
#else
#include <ctype.h>
#endif

/*
#ifndef WIN_PLATFORM
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#endif // WIN_PLATFORM
*/

//============================================================================
bool VxResolveHostToIp(	const char * pUrl,			//web name to resolve
					   std::string & strRetIp,		//return dotted string ( must be at least 16 bytes long )
					   U16& u16RetPort )			//return port ( May be null )
{
	std::string strHost;
	std::string strFileName;

	if( VxSplitHostAndFile( pUrl,
		strHost,
		strFileName,
		u16RetPort ) )
	{
		if( (':' == strHost.c_str()[0]) ||
			( isdigit( strHost.c_str()[0]) ) )
		{
			// already a ip address
			strRetIp = strHost;
			return true;
		}

		VxInetAddrAndPort oAddr;
		if( VxResolveHostToIp(	strHost.c_str(),			//web host name to resolve
			u16RetPort,
			oAddr ))
		{
			oAddr.toStdString( strRetIp );
			return true;
		}
	}
	return false;
}

//============================================================================
bool VxResolveHostToIp(	const char * pHostOnly,			//web host name to resolve
					   U16 u16Port,
					   VxInetAddress& oRetIp )
{
	if( VxIsAppShuttingDown() )
	{
		return false;
	}
	//resolve host into ip address
	struct addrinfo *res, *aip;
	struct addrinfo hints;
	SOCKET sock = -1;
	int error;

	/* Get host address. Any type of address will do. */
	memset(&hints, 0, sizeof(hints));
	hints.ai_flags = AI_ALL|AI_ADDRCONFIG;
	hints.ai_socktype = SOCK_STREAM;

	char as8Port[ 10 ];
	sprintf( as8Port, "%d", u16Port );

	error = getaddrinfo(pHostOnly, as8Port, &hints, &res);
	if (error != 0) 
	{
		log_msg( LOG_ERROR,
			"getaddrinfo: %s for host %s service %s\n",
			gai_strerror(error), pHostOnly, as8Port);
		return false;
	}
	bool bFoundAddr = false;;
	/* Try all returned addresses until one works */
	for (aip = res; aip != NULL; aip = aip->ai_next) 
	{
		if( VxIsAppShuttingDown() )
		{
			break;
		}
		/*
		* Open socket. The address type depends on what
		* getaddrinfo() gave us.
		*/
		sock = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol);
		if (sock == -1) 
		{
			perror("socket");
			freeaddrinfo(res);
			return false;
		}

		oRetIp.setIp( *((struct sockaddr_storage *)aip->ai_addr) );
		log_msg( LOG_DEBUG, "Resolve to %s\n", oRetIp.toStdString().c_str() );

		if( -1 == connect(sock, aip->ai_addr, (int)aip->ai_addrlen) ) 
		{
			perror("connect");
			VxCloseSkt( sock );
			sock = -1;
			continue;
		}

		// found ip
		bFoundAddr = true;
		VxCloseSkt( sock );
		break;
	}

	freeaddrinfo(res);
	return bFoundAddr;
}

//============================================================================
bool VxResolveHostToIps(	const char * pHostOnly,			//web host name to resolve
						U16 u16Port,
						std::vector<VxInetAddress>& aoRetIps )
{
	//resolve host into ip address
	struct addrinfo *res, *aip;
	struct addrinfo hints;
	SOCKET sock = -1;
	int error;

	aoRetIps.clear();

	/* Get host address. Any type of address will do. */
	memset(&hints, 0, sizeof(hints));
	hints.ai_flags = AI_ALL|AI_ADDRCONFIG;
	hints.ai_socktype = SOCK_STREAM;

	char as8Port[ 10 ];
	sprintf( as8Port, "%d", u16Port );

	error = getaddrinfo(pHostOnly, as8Port, &hints, &res);
	if (error != 0) 
	{
		log_msg( LOG_ERROR,
			"getaddrinfo: %s for host %s service %s\n",
			gai_strerror(error), pHostOnly, as8Port);
		return false;
	}
	/* Try all returned addresses until one works */
	for (aip = res; aip != NULL; aip = aip->ai_next) 
	{
		/*
		* Open socket. The address type depends on what
		* getaddrinfo() gave us.
		*/
		sock = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol);
		if (sock == -1) 
		{
			perror("socket");
			freeaddrinfo(res);
			return false;
		}

		/* Connect to the host. */
		if( -1 == connect(sock, aip->ai_addr, (int)aip->ai_addrlen) ) 
		{
			perror("connect");
			VxCloseSkt( sock );

			sock = -1;
			continue;
		}
		// found a ip
		VxInetAddress oAddr;
		oAddr.setIp( *((struct sockaddr_storage *)aip->ai_addr) );
		aoRetIps.push_back( oAddr );
	}
	freeaddrinfo(res);
	return aoRetIps.size() ? true : false;
}
